using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Shuriken.Core.Ranking;

namespace Shuriken.Core.UI.Controls
{
    /// <summary>
    /// Control to display underlined parts inside a text. 
    /// </summary>
    public class HitMaskLabel : LinkLabel 
    {
        public HitMaskLabel()
        {
            this.LinkArea = new System.Windows.Forms.LinkArea(0, 0);
            this.LinkBehavior = System.Windows.Forms.LinkBehavior.AlwaysUnderline;
            this.LinkColor = System.Drawing.Color.Black;
        }

        #region Properties
        /// <summary>
        /// Tells the color of the highlighted piece. 
        /// </summary>
        public Color HighlightColor
        {
            get { return this.DisabledLinkColor; }
            set { this.DisabledLinkColor = value; }
        }

        private MutableIndexSet m_hitMask;

        /// <summary>
        /// Hit mask to show what parts are highligted.
        /// </summary>
        public MutableIndexSet HitMask
        {
            get { return m_hitMask; }
            set { ChangeHitMask(value); }
        }
        
        #endregion

        /// <summary>
        /// changes the hitmask 
        /// </summary>
        /// <param name="hitMask">new hitmask</param>
        private void ChangeHitMask(MutableIndexSet hitMask)
        {
            if (hitMask == null)
            {
                m_hitMask = new MutableIndexSet();
            }
            else
            {
                m_hitMask = hitMask;
            }


            this.Links.Clear();

            List<Range> ranges = m_hitMask.GetRanges();
            List<Piece> pieces = CreatePieceList(this.Text, ranges);

            int link_index;

            for (int i = 0; i < pieces.Count; i++)
            {
                if (pieces[i].IsLink)
                {
                    link_index = this.Links.Add(new LinkLabel.Link(pieces[i].Location, pieces[i].Length));
                    this.Links[link_index].Enabled = false;
                }
            }
        }

        /// <summary>
        /// Creating a piece list from the ranges and text 
        /// </summary>
        /// <param name="text">text</param>
        /// <param name="ranges">ranges in the text</param>
        /// <returns>list of pieces</returns>
        private List<Piece> CreatePieceList(string text, List<Range> ranges)
        {
            List<Piece> pieces = new List<Piece>();
            Range r;
            Range nonlink_range;

            int cur_loc = 0;
            for (int i = 0; i < ranges.Count; i++)
            {
                r = ranges[i];

                // check if we have a non link before the range 
                if (cur_loc != r.Location)
                {
                    nonlink_range = new Range(cur_loc, r.Location - cur_loc);
                    pieces.Add(new Piece(nonlink_range, text, false));
                    cur_loc = r.Location;
                }

                pieces.Add(new Piece(r, text, true));
                cur_loc = r.Location + r.Length;
            }

            if (cur_loc < text.Length)
            {
                nonlink_range = new Range(cur_loc, text.Length - cur_loc);
                pieces.Add(new Piece(nonlink_range, text, false));
            }

            return pieces;
        }

        public override bool PreProcessMessage(ref Message msg)
        {
            bool result = base.PreProcessMessage(ref msg);

            // We are eating the keydown-enter message.
            if (msg.Msg == 0x100 && ((int)msg.WParam == (int)Keys.Enter))
            {
                return false; 
            }

            return result; 
        }
    }

    /// <summary>
    /// Represents a piece of the HitmaskLabel
    /// </summary>
    public class Piece
    {
        private int m_Length;
        private int m_Location;
        private string m_Text;
        private bool m_IsLink;
        private Region m_TextRegion;

        /// <summary>
        /// Length of piece 
        /// </summary>
        public int Length
        {
            get { return m_Length; }
            set { m_Length = value; }
        }

        /// <summary>
        /// Location of piece 
        /// </summary>
        public int Location
        {
            get { return m_Location; }
            set { m_Location = value; }
        }

        /// <summary>
        /// Text represented by this piece 
        /// </summary>
        public string Text
        {
            get { return m_Text; }
            set { m_Text = value; }
        }

        /// <summary>
        /// Flag to indicate if the piece is a link or not. 
        /// </summary>
        public bool IsLink
        {
            get { return m_IsLink; }
            set { m_IsLink = value; }
        }

        /// <summary>
        /// Range of the piece 
        /// </summary>
        public Range Range
        {
            get { return new Range(m_Location, m_Length); }
        }

        /// <summary>
        /// Region of the piece 
        /// </summary>
        public Region TextRegion
        {
            get { return m_TextRegion; }
            set { m_TextRegion = value; }
        }

        /// <summary>
        /// Piece constructor 
        /// </summary>
        /// <param name="r">Range of the piece</param>
        /// <param name="fullText">full text</param>
        /// <param name="IsLink">true, if it is a link</param>
        public Piece(Range r, string fullText, bool IsLink)
        {
            m_Location = r.Location;
            m_Length = r.Length;
            m_IsLink = IsLink;
            m_Text = fullText.Substring(m_Location, m_Length);
        }
    }
}
